import {
  TAG_HOST,
  TAG_TEXT,
  TAG_ROOT,
  ELEMENT_TEXT,
  PLACEMENT,
  UPDATE,
  DELETION,
} from './constants';
import { setProps } from './utils';
let nextUnitOfWork = null;
let workInProgressRoot = null;

export function scheduleRoot(rootFiber) {
  workInProgressRoot = rootFiber;
  nextUnitOfWork = rootFiber;
}

// 开始处理一个react element
function performUnitOfWork(currentFiber) {
  // 生成dom，并创建子节点
  beginWork(currentFiber);
  // 处理好自己后，如果有子节点，返回第一个子节点继续处理
  if (currentFiber.child) {
    return currentFiber.child;
  }

  while (currentFiber) {
    // 此时的currentFiber没有child节点，说明它本身已经处理完了，这时候可以收集副作用
    console.log('complete', currentFiber);
    completeUnitOfWork(currentFiber);
    if (currentFiber.sibling) {
      return currentFiber.sibling; // 返回到兄弟节点继续处理（performUnitOfWork）
    }
    currentFiber = currentFiber.return;
  }
}

// 构建以链表
function completeUnitOfWork(currentFiber) {
  const returnFiber = currentFiber.return;
  if (returnFiber) {
    // 1 连接两条链表（fiber本身的和returnFiber的）
    /* 
      firstEffect: head指针
      nextEffect: next
      lastEffect: tail指针
    */
    if (!returnFiber.firstEffect) {
      // 连接到链表头
      returnFiber.firstEffect = currentFiber.firstEffect;
    }

    if (currentFiber.lastEffect) {
      // 说明currentFiber存在一个链表，需要连接
      if (returnFiber.lastEffect) {
        // 需要连接两个链表
        returnFiber.lastEffect.nextEffect = currentFiber.firstEffect;
      }
      returnFiber.lastEffect = currentFiber.lastEffect;
    }

    // 2 将currentFiber插入链表中
    if (currentFiber.effectTag) {
      if (returnFiber.lastEffect) {
        returnFiber.lastEffect.nextEffect = currentFiber;
      } else {
        returnFiber.firstEffect = currentFiber;
      }
      // curretn插入后，修改last指针
      returnFiber.lastEffect = currentFiber;
    }
  }
}
/* 
  1 创建dom元素
  2 创建子fiber
*/
function beginWork(currentFiber) {
  switch (currentFiber.tag) {
    case TAG_ROOT: {
      updateHostRoot(currentFiber);
      break;
    }
    case TAG_HOST: {
      updateHost(currentFiber);
      break;
    }
    case TAG_TEXT: {
      updateHostText(currentFiber);
      break;
    }
    default: {
    }
  }
}

function updateHostRoot(fiber) {
  const newChildren = fiber.props.children;
  reconcileChildren(fiber, newChildren);
}

function updateHostText(fiber) {
  if (!fiber.stateNode) {
    //如果此fiber没有创建DOM节点
    fiber.stateNode = createDom(fiber);
  }
}
function updateHost(fiber) {
  if (!fiber.stateNode) {
    fiber.stateNode = createDom(fiber);
  }
  const newChildren = fiber.props.children;
  reconcileChildren(fiber, newChildren);
}

function createDom(fiber) {
  if (fiber.tag === TAG_TEXT) {
    return document.createTextNode(fiber.props.text);
  } else if (fiber.tag === TAG_HOST) {
    const stateNode = document.createElement(fiber.type);
    updateDOM(stateNode, {}, fiber.props);
    return stateNode;
  }
}

function updateDOM(dom, oldProps, newProps) {
  setProps(dom, oldProps, newProps);
}

function reconcileChildren(currentFiber, children) {
  let index = 0;
  let prevSibling = null;
  while (index < children.length) {
    const element = children[index];
    let tag;
    if (element.type === ELEMENT_TEXT) {
      tag = TAG_TEXT;
    } else if (typeof element.type === 'string') {
      tag = TAG_HOST;
    }
    const fiber = {
      tag,
      type: element.type,
      props: element.props,
      stateNode: null,
      return: currentFiber,
      effectTag: PLACEMENT,
      nextEffect: null,
    };

    if (index === 0) {
      currentFiber.child = fiber;
    } else {
      prevSibling.sibling = fiber; // 构建关系
    }
    prevSibling = fiber;
    index++;
  }
}
// 循环处理react element形成fiber树，并收集副作用链
function workLoop(deadline) {
  let shouldYield = false;
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    shouldYield = deadline.timeRemaining() < 1;
  }

  if (!nextUnitOfWork && workInProgressRoot) {
    // 完成diff阶段
    console.log('render阶段结束');
    commitRoot();
  }
  // 继续下个时间片处理
  requestIdleCallback(workLoop, { timeout: 500 });
}

function commitRoot() {
  let currentFiber = workInProgressRoot.firstEffect;
  while (currentFiber) {
    console.log('commit fiber', currentFiber);
    commitWork(currentFiber);
    currentFiber = currentFiber.nextEffect;
  }
  workInProgressRoot = null;
}

function commitWork(fiber) {
  if (!fiber) return;
  // 处理fiber的更新操作等
  const parentDom = fiber.return.stateNode;
  const stateNode = fiber.stateNode;
  if (fiber.effectTag === PLACEMENT) {
    // 添加节点
    parentDom.appendChild(stateNode);
  }
  fiber.effectTag = null;
}
// 开始执行
requestIdleCallback(workLoop, { timeout: 500 });
